iT邦幫忙

2021 iThome 鐵人賽

DAY 25
2

https://ithelp.ithome.com.tw/upload/images/20211010/20113277e2qr4qq6qt.png

基本上 CDN 是現在的 Web 應用不可或缺的技術,當對被 CDN 加速過的域名發出請求時,CDN 會自動將 request 導到地理位置離使用者較近或是流量較不吃緊的 edge server 來處理,這在 Day20 時有詳細介紹過。

我以前總是把 CDN 單純看作是一種分散式的快取伺服器,沒有想過它還能做到什麼很酷炫的事情,直到之前研究了一下 AWS 的 Lambda@Edge 才開啟了自己的視野。原來 CDN 的 edge server 還能用來執行 serverless 的 function,因此可以做到例如修改 request 與 response 的 header、動態產生內容或是在 edge server 這層做 access control 等等事情。有趣的是不只 AWS 的 Lambda@Edge,目前越來越多的 cloud provider 推出了可以在 edge server 進行運算或執行 serverless function 的服務,例如最近蠻紅的 Cloudflare Workers 就是有名的 CDN provider Cloudflare 推出的服務。

如果對於 CDN edge server 可以跑 serverless function 或可以做到什麼事情一點概念也沒有的朋友,可以參考我之前的文章 - Coding Your CDN ! 充滿驚奇的 AWS Lambda@Edge

回過頭看今天想要討論的主題,談到現階段的前端開發架構,基本上都會得到這三個名詞:CSR、SSR、SSG。尤其像是 Next.js 或是 Nuxt.js 這些最近很流行的 SSR 框架更提供我們可以做到根據 page level 將以上三種架構混合使用的方式,這些也正是昨天介紹過的。

等等,CDN edge server 跟前端架構又有什麼關係…?還有怎麼一直在講前幾天的內容,是不是想騙讀者的時間?

在 CDN Edge Server 可以做的事越來越多後,一種新的架構觀念被提出了 — Edge Side Rendering (ESR,也有一種說法是 Edge Slice Re-Rendering)。
ESR 這個概念老實說還不普及,雖然已經有一些 CDN Provider 或提供 SaaS 服務的企業有推出一些 ESR 的解決方案,但還是相對不成熟,或是沒辦法跟大多數開發者在使用的熱門前端框架例如 Next.js 或 Nuxt.js 完美結合。不過我個人還是非常期待它的未來發展,也一直深信未來 serverless 相關技術會大大改變技術開發的生態系,因此才會在這個技術還不成熟的狀況下就選擇分享它的概念,如果看到這裡你還有興趣,就一起來探索這個新的概念吧!

So, what are the problems with the original architectures ?

一個架構概念的誕生照理來說就是為了解決原有架構存在的一些問題,所以在介紹 ESR 之前我們先來看看現有架構存在的一些問題。

Client Side Rendering (CSR)

CSR 最為人詬病的當然還是 SEO 的問題,不過這個問題隨著搜尋引擎的演進也許在未來有機會被解決掉。從上面這張圖可以看到 CSR 常常會搭配 CDN 來快取靜態的 HTML 檔案,當使用者發出請求時,如果 CDN Cache 裡有資料就可以快速回傳靜態的 HTML 給使用者,再透過在 client 端發起非同步的請求來抓取動態的資料並渲染到頁面上。先撇開 SEO 不談,這個架構可能會有的問題是在渲染內容到頁面之前需要先下載 JavaScript bundle 再發起 Ajax 請求,因此 First Meaningful Paint 在 CSR 上通常會比較久,如果 bundle size 很肥大又沒有做好 code splitting,頁面完成渲染的時間又會再加長。

SSR With Client Side Hydration

這邊指的不是傳統完全靠 server side 產生頁面的 SSR,而是 Isomorphic JavaScript 這種在後端產生 HTML 並帶入基本資料,再到前端做 Rehydrate ,由 CSR 接管頁面後續渲染的混合式 SSR。我想會對這篇文章有興趣的讀者應該都了解這種 SSR 的基本概念了,所以就不再贅述。這種架構會產生哪些問題呢?雖然採用這種架構相對於 CSR 因為一開始頁面就會有內容,所以會有比較好的 FCP (First Contentful Paint),但是因為要等到 JS bundle 加載完成並在 client side hydrate 過後頁面才能夠互動,因此 TTI (Time to Interactive)會被拉長,有可能導致使用者已經可以看到頁面內容,卻沒辦法與頁面產生互動的狀況。另外因為每次都要在 server 產生內容,SSR 的 Time To First Byte 也會稍微慢一點。

因為 SSR 是透過每次請求都到 origin sevrer 去動態生成一次內容,當流量一大也會對這個 renderer server 產生一定的負擔。再者如果這個 renderer server 在地理位置上沒有那麼接近使用者,也會對傳輸過程產生一些延遲。最後因為某些經過 SSR 動態產生的頁面內容可能常常會需要改變,所以並沒有那麼適合放到 CDN 快取裡,也就沒辦法享受到 CDN 的好處。(依照專案需求,有時候還是可以把一些不常變動的頁面的 SSR 執行結果存到 renderer server 的 cache 裡或是加一層 caching layer 並設置很短的 TTL)

Static Site Generation (SSG)

SSG 是三者中效能最好的一種方式,透過在 build time 就產生靜態頁面的方式,SSG 可以達到最好的 Time To First Byte,並且可以將生成的靜態網站 host 到像是 netlify 這種 static hosting 的平台或是 CDN 上。

SSG 看似美好,但它仍然有些限制 :

  • 沒辦法像 SSR 那樣有動態內容的彈性
  • 當內容需要改變,就必須重新 build 頁面
  • 如果網站很巨大,build time 會很長

後來也出現一些新的架構思想想要解決 SSG 的一些問題,例如 Incremental Static Regeneration (ISR,昨天有稍微做了基本介紹) 與 Distributed Persistent Rendering (DPR),有興趣的讀者可以再自行研究囉!

看完這三種架構各自可能會產生的問題,我們可能會想問

有沒有辦法在保持 SSG 效能的同時,又同時保持 SSR 對於動態內容的彈性?

Yes, ESR comes to the rescue.

ESR (Edge Side Rendering | Edge Slice Re-rendering)

關於 ESR,比較了一下現有的解決方案,有的人稱它為 Edge Side Rendering,也有人稱它為 Edge Slice Re-rendering。雖然實作方式可能有些許不同,不過底層概念都是利用 CDN edge server 的計算能力,把以往需要在 origin server 執行的操作拉到 CDN level 處理,除了離 end user 較近以外,還能充分運用 CDN 快取帶來的優勢。今天主要會聚焦在 Vercel YouTube 頻道中其中一支影片介紹的 Edge Slice Re-rendering 架構。

假設你建立了一個線上技術分享會的網站

例如像上圖這樣子,在網頁的下方會有一個 footer,在空閒時間顯示下一場演講的主題,如果有一場演講正在進行,則會顯示 Live 來表示正在進行哪場分享。

看到這種需要變動內容的需求,你可能會想到兩種方式:

  • client side rendering
  • server side rendering

雖然兩種方式照理來說都可以完成需求,但剛剛也提過它們各自帶來了一些 trade off


(client side execution)

在 client side 執行很有可能延遲頁面的載入時間並且導致頁面閃爍,這些問題在某些類型的網站可能還可以接受,但如果是電商這種平台可能就要盡量避免了。


(server side execution)

再來看看 SSR,雖然這個頁面會變動,但是改動的頻率似乎也不會太高,況且改變的其實只是頁面的小部分,為了這樣的改變去做 SSR,帶來的成本可能是沒辦法搭配 CDN 做快取或是重複的 re-render 頁面中不會變動的部分,看起來也不是一個最佳解法。

也許這時候你也想到了 SSG,如過按照我們對 SSG 的認識,似乎每次更改一次 footer 的狀態就得重新 build 一次頁面,雖然像 Next.js 這種框架可以做到 page level 的 rebuild 而不用重新 build 整個網頁,不過這樣的更動頻率對靜態網站來說似乎還是有點太高了。

回想一下我們剛剛的問題

我們希望可以保有 SSR 的彈性,卻可以達到 SSG 的效能。

讓我們先看看這個 footer component 的程式碼,既然是顯示議程的資訊,姑且先叫它 Agenda 吧!

而它的使用方式大致上是這樣

從這個 component 實作的方式我們大概可以歸納出一個觀念,就是我們只想要 re-render 頁面上的某些片段 (slice) 而已,以這個例子來說就是傳入的 props 的部分 — linkURL、title、children,這個 component 的其他部分與頁面上的其他元件因為沒有改動,所以希望可以用 SSG 的方式 build 成靜態內容。

不過要怎麼決定我們只想要 re-render 頁面中的哪些部分呢?在 vercel 發佈的這支影片中,作者提到他們是使用 compiler 的靜態分析的方式做到的,這邊因為比較 hard code 就不再這邊多做討論了,大家只要先 focus 在「我們希望頁面改動時只 re-render 部分內容」這個重點就好。

至於只 re-render 部分內容這個操作又被定義出一個叫做 override 的行為,一個 override 的基本結構如下

在這個物件中,重點應該是 compute 這個 function,我們可以在這個 function 做一些計算或操作並返回新的 props。

看起來挺直觀的,不過問題來了,這個 override 的行為應該要在哪裡執行比較好?

client side 嗎?前面已經討論過它的問題,看起來不太適合。
server side 嗎?看起來也沒辦法避免它自身會產生的問題,更沒辦法達到保有 SSR 的彈性,卻可以達到 SSG 的效能這個期望。

Maybe…we can do it at the CDN edge.

到這裡才算是真的帶出 ESR 這個詞,不過影片中的作者有提到,通常不會單獨使用 Edge Slice Re-rendering,而是會搭配 SSR 或 SSG 使用。以前面分享會的例子來說,可以先使用 SSG build 出靜態的頁面,並把靜態的頁面放到 CDN Cache 上,當頁面有變動需求時再對 CDN edge server 發出 override 請求,並在 edge server 完成計算得到新的 props 並渲染到頁面上。

觀察一下各種架構的 benchmark,SSG 加上 ESR 的方式非常有機會可以達到前面說的「希望可以達到 SSR 的動態彈性,又能維持 SSG 的效能」的期望。

其他的解決方案

Edge Slice Re-rendering 只是其中一個被提出來的解決方案,也有人提出的解決方案叫 Edge Side Rendering,實作細節可能稍微有些許不同,但是本質上都是利用 CDN edge server 的計算能力與更接近使用者的特性來提升網站的性能。

Flareact

Edge-rendered React framework built for Cloudflare Workers

在文章的開頭有提到由 CDN provider Cloudflare 推出的 serverless 服務 — Cloudflare Workers,而 Flareact 則是一個利用 Cloudflare Workers 的 edge-rendered React framework,基本上它借鏡了許多 Next.js 的開發方式與習慣,如果熟悉 Next.js 的人應該可以快速上手,想了解更多關於 Flareact 的讀者可以參考這裡

在過去,dynamic content 一般被認為是不太能被被快取的,不過最近 CDN serverless service 的發展,讓這個限制也慢慢消失了,現在動態的內容也有機會可以透過快取來減少網站的 latency,有興趣的讀者可以看看 Cloudflare Workers 的這篇文章

Edge Side Rendering

這篇文章中,作者提出可以透過 ESI (Edge Side Includes) 這種 markup language (已向 w3c 提出成為 web 標準的申請,但一直沒有得到正式批准)來區分出頁面中的靜態內容與動態內容並順利組合在一起。

這種方式可以讓靜態內容被 cache 在 CDN 裡,當使用者對頁面發出請求時,就先回傳被快取的靜態內容版本,接著由 CDN layer 負責去集結動態內容,並採用 streaming 的方式回傳給 end users。

有興趣的讀者可以到這篇文章看看。

本日小結

這應該是我第一次嘗試用文章的形式分享一個尚未成熟的技術,過程中能參考的資料不多,比起以往介紹熱門技術的文章更艱難了一點,如果有哪邊有錯誤還請不吝指正。

像 AWS Lambda@Edge、Cloudflare Workers 這些 based on CDN 的 serverless 服務越來越成熟後,能透過 CDN edge server 做到的事情也越來越多了,這次得知還能在 edge side 做前端頁面的渲染來提升效能時還蠻驚訝又興奮的,雖然 ESR 是相對新又還不成熟的技術,但我個人還是很期待它未來能變出什麼新花樣,或是能不能讓頁面效能再達到一個新高度。希望本篇文章可以激起你對 ESR 的興趣,一起關注它的未來發展吧!

2021/10/27 完賽後更新

在昨天 10/26 Next.js 推出了第 12 版,其中一個功能是 middleware,其實跟 AWS Lambda@Edge 與 Cloudflare Workers 等運用 edge server 的 edge function 非常類似,開發 Next.JS 的公司 Vercel 的 CEO 也在 Conference 中說他們相信 web 的未來將會在雲端上,看來前端開發者必須學習這些 Serverless 相關的技術並跨越原本單純負責畫面的職責似乎變成一種勢在必行的趨勢了呢。

References & 圖片來源

https://www.cloudflare.com/zh-tw/learning/cdn/caching-static-and-dynamic-content/
https://blog.cloudflare.com/rendering-react-on-the-edge-with-flareact-and-cloudflare-workers/


上一篇
Day24 X Web Rendering Architectures
下一篇
Day26 X Memory Management In JavaScript
系列文
今晚,我想來點 Web 前端效能優化大補帖!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言